# Digital to Analog
# TLC5620

# TLC5620           Pi
# CLK(7)    -----   Pin37
# DATA(6)   -----   Pin38
# LOAD(8)   -----   Pin40

# VDD(14)   -----   5V
# GND(1)    -----   GND
# LDAC(13)  -----   GND
# REFA(2)   -----   3.3V
# DACA(12)  -----   Analog Output

import RPi.GPIO as GPIO

# 引脚定义（BCM编号模式）
DAC_CLK=26   # 对应物理引脚37（BCM26）
DAC_DATA=20  # 对应物理引脚38（BCM20）
DAC_LOAD=21  # 对应物理引脚40（BCM21）

def setup(clk=26,data=20,load=21): #37,38,40 参数为BCM引脚号
    global DAC_CLK,DAC_DATA,DAC_LOAD
    DAC_CLK=clk    # 设置时钟引脚
    DAC_DATA=data   # 设置数据引脚 
    DAC_LOAD=load   # 设置加载引脚
    GPIO.setwarnings(False)  # 禁用GPIO警告
    GPIO.setmode(GPIO.BCM)   # 使用BCM编号模式
    GPIO.setup(DAC_CLK,GPIO.OUT)  # 配置CLK为输出
    GPIO.setup(DAC_DATA,GPIO.OUT) # 配置DATA为输出
    GPIO.setup(DAC_LOAD,GPIO.OUT) # 配置LOAD为输出
    
def destroy():
    GPIO.cleanup()  # 清理GPIO状态
    
def SendOneData(num,a1=0,a0=0,rng=0):
    # 遵循TLC5620时序要求来模拟实现通信
    GPIO.output(DAC_LOAD,1)  # 初始状态保持LOAD高电平
    
    # 给 DATA 端口依次输入 a1, a0, rng
    # a1 和 a0 用于选择通道，由于二者均为 0，故选的是 DACA
    
    #通道选择A1
    GPIO.output(DAC_DATA,a1)      # 设置A1电平
    GPIO.output(DAC_CLK,1)        # 时钟上升沿锁存
    GPIO.output(DAC_CLK,0)   # Output A1       
    # 下降沿准备下一位
    
    #通道选择A0
    GPIO.output(DAC_DATA,a0)      # 设置A0电平
    GPIO.output(DAC_CLK,1)
    GPIO.output(DAC_CLK,0)  # Output A0
    
    #范围选择RNG
    GPIO.output(DAC_DATA,rng)     # 设置RNG电平
    GPIO.output(DAC_CLK,1)
    GPIO.output(DAC_CLK,0)  # Output RNG
    
    ''' 依次取 num 各位，相当于不断左移，并把多出的高位削去，保证当前位在最高位'''
    # 发送8位数据（MSB优先）
    i=8
    while i>0:
        num=num%256       # 确保数值在8位范围内（0-255）
        this_bit=int(num/128)  # 获取最高位（128=2^7）
        GPIO.output(DAC_DATA,this_bit)  # 输出当前最高位
        GPIO.output(DAC_CLK,1)  # 时钟上升沿锁存数据位
        GPIO.output(DAC_CLK,0)  # 下降沿准备下一位
        # Output Di
        num=num<<1        # 左移获取下一个最高位
        i=i-1             # 剩余位数减1
    # 将 LOAD 设为高电平时，把数据锁存至串行数据寄存器中，低电平时加载数据到DAC寄存器
    GPIO.output(DAC_LOAD,0)  # LOAD下降沿触发数据锁存
    
    
def loop():
    while 1:  # 无限循环
        num=int(input("input a integer(0~255):"))  # 获取用户输入
        SendOneData(num)  # 发送到DAC
        
if __name__ == '__main__':
    setup()  # 初始化GPIO
    try:
        loop()  # 进入主循环
    except KeyboardInterrupt:
        destroy()  # 异常退出时清理